package com.aos.iot.socket.tcp;

import com.aos.iot.socket.tcp.properties.SocketTcpProperties;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.PostConstruct;

@Slf4j
@RequiredArgsConstructor
public class SocketTcpServer {

    private final EventLoopGroup tcpBossGroup;

    private final EventLoopGroup tcpWorkerGroup;

    private final ChannelInitializer<? extends Channel> channelInitializer;

    private final SocketTcpProperties socketTcpProperties;

    private ServerBootstrap bootstrap;

    @PostConstruct
    public void init() {
        bootstrap = new ServerBootstrap()
                .group(tcpBossGroup, tcpWorkerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 2048)
                .option(ChannelOption.SO_REUSEADDR, true)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,30000)
                .option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024, 5 * 1024 * 1024))
                .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childHandler(channelInitializer);
    }

    public void start() throws InterruptedException {
        bootstrap.bind(socketTcpProperties.getHost(), socketTcpProperties.getPort())
                .sync()
                .addListener(future -> {
                    if (future.isSuccess()) {
                        log.info("Socket Tcp server started at port: {}", socketTcpProperties.getPort());
                    }
                });
    }

    @SneakyThrows
    public synchronized void stop() {
        tcpWorkerGroup.shutdownGracefully().await();
        tcpBossGroup.shutdownGracefully().await();
    }

}
